using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace Mud.Common.Messages
{

    /// <summary>
    /// Constructs messages from their serialized state.
    /// </summary>
    public static class MessageFactory
    {

		private static Dictionary<int, ConstructorInfo> _messageConstructors = new Dictionary<int, ConstructorInfo>();

		/// <summary>
		/// Associates a class with specific message type by using reflection.
		/// </summary>
        static MessageFactory()
        {
			Type[] allTypes = Assembly.GetExecutingAssembly().GetTypes();
			foreach (Type type in allTypes) {
				if (!typeof(IMessage).IsAssignableFrom(type)) // go through only IMessage derived classes
					continue;
				object[] attributes = type.GetCustomAttributes(typeof(MessageAttribute), false);
				if (attributes == null || attributes.Length != 1)
					continue;
				_messageConstructors.Add((int)((MessageAttribute)attributes[0]).MessagetTypeId, type.GetConstructor(Type.EmptyTypes));
			}
		}

		/// <summary>
		/// Creates a new message out of deserialized message.
		/// </summary>
        /// <param name="package">Package out of which to create the message.</param>
        /// <returns>Deserialized message or null if the message can not be deserialized.</returns>
        public static IMessage DeserializeMessage(BytePackage package)
        {
            // first 4 bytes of the serialized message should be the 
            int messageTypeId = package.PeekInt();

            ConstructorInfo constructor = null;
			if (!_messageConstructors.TryGetValue(messageTypeId, out constructor))
            {
                Logger.Log(LogType.Warning, "MessageFactory", "No handler found for message {0}.", messageTypeId);
                return null;
            }
			IMessage message = (IMessage)constructor.Invoke(null);
            message.Deserialize(package);
            return message;
        }


    }

}
